import { Scene } from '@babylonjs/core/scene';
import { AbstractControl, IAbstractControlOptions } from './abstract-control';
import { Control } from '@babylonjs/gui/2D/controls/control';
import { StackPanel } from '@babylonjs/gui/2D/controls/stackPanel';
import { TextBlock } from '@babylonjs/gui/2D/controls/textBlock';
import { Rectangle } from '@babylonjs/gui/2D/controls/rectangle';
import { CreateHandleTo, IHandle, RemoveHandle } from '../../data/data-handle';


/**
 * 开关按钮控件
 * @param title 标题内容
 * @param debug 调试绘制（仅开发中使用）
 * @param isVertical 是否垂直布局
 * @param spacing 文字内容与按钮的间隔留白
 * @param fontSize 字体大小
 * @param fontColor 字体颜色
 * @param fontFamily 字体
 * @param onColor 打开状态时的颜色
 * @param offColor 关闭状态时的颜色
 * @param frontColor 控制块的颜色
 * @param toggleSize 开关大小
 * @param isOn 是否开启
 */
interface IUIToggleOptions extends IAbstractControlOptions {
    title?: string,
    debug?: boolean,
    isVertical?: boolean,
    spacing?: number,
    fontSize?: number,
    fontColor?: string,
    fontFamily?: string,
    onColor?: string,
    offColor?: string,
    frontColor?: string,
    toggleSize?: number,
    isOn?: boolean
}


/**
 * 开关控件
 * @param name 名称
 * @param scene 所在场景
 * @param options 参数对象
 */
class UIToggle extends AbstractControl {

    private _changeHandles: Array<IHandle<boolean>> = [];
    private _value!: boolean;
    private _fontSize!: number;
    private _toggleWidth!: number;
    private _toggleHeight!: number;
    private _borderWidth!: number;
    private _onColor!: string;
    private _offColor!: string;
    private _isEnabled!: boolean;
    private _frontColor!: string;
    private _fontColor!: string;

    /**
     * 开关后侧原始控件
     */
    public toggleBack!: Rectangle;

    /**
     * 开关前侧原始控件
     */
    public toggleFront!: Rectangle;

    /**
     * 页眉（标题）原始控件
     */
    public header!: TextBlock;

    constructor(name: string, scene: Scene, options?: IUIToggleOptions) {
        super(name, scene, options);
        this.toggleBack.onPointerDownObservable.add(this.breakCamera);
        this.toggleFront.onPointerDownObservable.add(this.breakCamera);
        this.header.onPointerDownObservable.add(this.breakCamera);

        this._value = options ? (!!options.isOn) : false;
        this._value ? this.stateOnStyle() : this.stateOffStyle();
    }

    public set isEnabled(enabled: boolean) {
        this._isEnabled = enabled;
        if (this.enabledStyle) this.enabledStyle(enabled, this);
    }
    public get isEnabled(): boolean {
        return this._isEnabled;
    }

    /**
     * 设置开启状态
     */
    public set isOn(isOn: boolean) {
        if (!this.isEnabled) return;
        this._value = isOn;
        this._value ? this.stateOnStyle() : this.stateOffStyle();
        if (!this.avoidEventHandle) this._changeHandles.forEach(handle => handle.callback(this._value));
    }

    /**
     * 获取开启状态
     */
    public get isOn(): boolean {
        return this._value;
    }

    /**
     * 添加开启状态改变时的回调函数对象
     * @param func 回调函数
     * @returns 回调函数对象
     */
    public onChange(func: { (isOn: boolean): void }): IHandle<boolean> {
        return CreateHandleTo(func, this._changeHandles);
    }

    /**
     * 移除开启状态改变时的回调函数对象
     * @param handle 回调函数对象或其id
     */
    public removeChangeHandle(handle: number | IHandle<boolean>): void {
        RemoveHandle(handle, this._changeHandles);
    }

    protected initializeControl(name: string, scene: Scene, options: IUIToggleOptions): Control {

        this._value = false;
        this._fontSize = options.fontSize || 26;
        this._toggleWidth = options.toggleSize ? options.toggleSize * 52 / 32 : this._fontSize * 2;
        this._toggleHeight = options.toggleSize || this._fontSize * 32 / 26;
        this._borderWidth = options.toggleSize ? options.toggleSize * 4 / 32 : this._fontSize * 4 / 26;
        this._onColor = options.onColor || '#aaaaaa';
        this._offColor = options.offColor || '#000000';
        this._frontColor = options.frontColor || '#ffffff';
        this._fontColor = options.fontColor || '#000000';

        const panel = new StackPanel(name + '-panel');
        panel.isVertical = options.isVertical || false;
        if (options.debug) panel.background = '#ff00ff';

        const toggleBack = new Rectangle(name + '-toggle-back');
        const bw = this._toggleWidth;
        const bh = this._toggleHeight;
        const lw = this._borderWidth;
        toggleBack.width = bw + 'px';
        toggleBack.height = bh + 'px';
        toggleBack.background = this._offColor;
        toggleBack.cornerRadius = bh;
        toggleBack.thickness = 0;
        this.toggleBack = toggleBack;
        panel.addControl(toggleBack);

        const toggleFront = new Rectangle(name + '-toggle-front');
        const fs = (bh - lw * 2);
        toggleFront.width = fs + 'px';
        toggleFront.height = fs + 'px';
        toggleFront.cornerRadius = fs;
        toggleFront.left = lw * 0.5 + 'px';
        toggleFront.background = this._frontColor;
        toggleFront.thickness = 0;
        this.toggleFront = toggleFront;
        toggleBack.addControl(toggleFront);

        const header = new TextBlock(name + '-header');
        header.text = options.title || 'toggle';
        header.fontSize = this._fontSize + 'px';
        header.color = this._fontColor;
        header.fontFamily = options.fontFamily || 'Arial';
        header.width = this._fontSize + 'px';
        header.height = this._fontSize + 'px';
        header.clipContent = false;
        this.header = header;
        panel.addControl(header);

        const space = options.spacing || 5;
        UIToggle.autoLayout(panel, header, space, [header], [toggleBack, toggleFront]);

        return panel;
    }

    /**
     * 设置开启状态样式
     */
    private stateOnStyle(): void {
        this.toggleFront.left = (this._toggleWidth - this._toggleHeight + this._borderWidth * 1.5) + 'px';
        this.toggleBack.background = this._onColor;
    }

    /**
     * 设置关闭状态样式
     */
    private stateOffStyle(): void {
        this.toggleFront.left = this._borderWidth * 0.5 + 'px';
        this.toggleBack.background = this._offColor;
    }

    protected bindEvent(control: Control, options: IUIToggleOptions): void {
        (control as StackPanel).onPointerClickObservable.add(() => {
            if (!this._isEnabled) return;
            this._value = !this._value;
            this._value ? this.stateOnStyle() : this.stateOffStyle();
            if (!this.avoidEventHandle) this._changeHandles.forEach(handle => handle.callback(this._value));
        });
    }

    protected unbindEvent(control: Control): void {
        super.unbindEvent(control);
        (control as StackPanel).onPointerClickObservable.clear();
    }

}


/**
 * 创建开关控件
 * @param name 名称
 * @param scene 所在场景
 * @param options 参数对象
 * @param changeCallback 状态改变时的回调函数
 * @returns 开关控件
 */
const CreateUIToggle = (name: string, scene: Scene, options?: IUIToggleOptions, changeCallback?: { (isOn: boolean): void }): UIToggle => {
    const toggle = new UIToggle(name, scene, options);
    if (changeCallback) toggle.onChange(changeCallback);
    return toggle;
};


export { UIToggle, CreateUIToggle };
export type { IUIToggleOptions };